﻿using codeparser.net.v2.Exceptions;
using codeparser.net.v2.SyntaxHighlighter;

using System;
using System.Collections.ObjectModel;
using System.Globalization;

namespace codeparser.net.v2.Entities
{
    /// <summary>
    /// Represents a tag tree node.
    /// </summary>
    internal class TreeNodeTag : ITreeNode
    {
        /// <summary>
        /// Gets or sets the tag.
        /// </summary>
        /// <value>The tag.</value>
        public Tag Tag
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the tag configuration.
        /// </summary>
        /// <value>The tag configuration.</value>
        public TagConfiguration TagConfiguration
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the list of attributes.
        /// </summary>
        /// <value>A list of attributes.</value>
        public Collection<TagAttribute> Attributes
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the parent node.
        /// </summary>
        /// <value>The parent node.</value>
        public ITreeNode Parent
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the list of subordinate nodes.
        /// </summary>
        /// <value>The subordinate nodes.</value>
        public Collection<ITreeNode> Nodes
        {
            get;
            set;
        }

        /// <summary>
        /// Returns a string representation of the current node.
        /// </summary>
        /// <returns>A string representation.</returns>
        public override string ToString()
        {
            // Check whether there are any rules for the current tag. If not, throw an exception.
            if (this.Tag != null && this.Tag.Rules.Count == 0)
            {
                throw new MissingRuleException(String.Format(CultureInfo.CurrentCulture,
                    "Missing rule for tag '{0}'", this.Tag.Element.Name));
            }

            // Create the different parts of the tag.
            string openingTag = "";
            string content = "";
            string closingTag = "";
            
            // If the current node has a tag, get the opening and closing tag.
            TagRule rule = null;
            if (this.Tag != null)
            {
                // Get the appropriate rule.
                rule = this.Tag.GetRule(this.Attributes);

                // Build the opening tag.
                openingTag = rule.OpeningTagRule;
                closingTag = rule.ClosingTagRule ?? "";
                foreach (TagAttribute attribute in this.Attributes)
                {
                    openingTag = openingTag.Replace("${" + attribute.Name + "}", attribute.Value ?? attribute.Name);
                    closingTag = closingTag.Replace("${" + attribute.Name + "}", attribute.Value ?? attribute.Name);
                }
            }

            // If the tag is not a single tag, get the content.
            if (this.Tag == null || (this.Tag != null && this.Tag.ClosingTagStyle != TagClosingStyle.None))
            {
                // Iterate over all subordinate nodes.
                foreach (ITreeNode node in this.Nodes)
                {
                    content += node.ToString();
                }

                // Insert the content within the opening and the closing tag.
                openingTag = openingTag.Replace("${content}", content);
                closingTag = closingTag.Replace("${content}", content);
            }

            // Check whether the content should be syntax highlighted. If so, do it.
            if (rule != null)
            {
                switch(rule.SyntaxHighlighter)
                {
                    case SyntaxHighlighterStrategy.Wilco:
                        SyntaxHighlighterBase syntaxHighlighter =
                            new WilcoSyntaxHighlightingAdapter(rule.SyntaxHighlighterLanguage);
                        content = syntaxHighlighter.Highlight(content);
                        break;
                    case SyntaxHighlighterStrategy.None:
                        break;
                    default:
                        break;
                }
            }

            // Create the result string.
            string result = openingTag + content + closingTag;

            // Return the result to the caller.
            return result;
        }

        /// <summary>
        /// Initializes a new instance of the TreeNodeTag type.
        /// </summary>
        /// <value>The element.</value>
        /// <param name="parent">The parent node.</param>
        /// <param name="tag">The tag.</param>
        /// <param name="tagConfiguration">The tag configuration.</param>
        public TreeNodeTag(ITreeNode parent, Tag tag, TagConfiguration tagConfiguration)
        {
            // Initialize the fields.
            this.Nodes = new Collection<ITreeNode>();
            this.Attributes = new Collection<TagAttribute>();
            this.Parent = parent;
            this.Tag = tag;
            this.TagConfiguration = tagConfiguration;
        }
    }
}